package mosquito.g7;

import java.util.HashSet;
import java.util.Set;
import java.awt.geom.Line2D;
import java.awt.geom.Point2D;

import mosquito.g7.StaticZap.EBOOL;

public class Pixel {
    
    private int internalX, internalY;
    private double x, y; 
    private double percentInShadow;
    private Set<Line2D> linesWithinRadius;
    private Board board;
    private EBOOL isOnALine;
    private boolean doNotPlaceLight;
    private double distanceFromWall;
    private double distanceFromAllWalls;
    
    public Pixel(double x, double y, int internalX, int internalY, Board board){
        this.x = x;
        this.y = y;
        this.internalX = internalX;
        this.internalY = internalY;
        this.board = board;
        percentInShadow = -1; // initial value
        isOnALine = StaticZap.EBOOL.UNKNOWN;
        doNotPlaceLight = false;
    }
    
    public void neverPlaceLightHere() {
        doNotPlaceLight = true;
    }
    
    public void clearNeverPlaceLightHere() {
        doNotPlaceLight = false;
    }


    public boolean shouldTryToPlaceLightHere() {
        return !(doNotPlaceLight || isOnALine());
    }

    private void setIsOnALine() {
        setPercentInShadow(); // gross... I know
    }
    
    // side effect is setting of isOnALine
    private void setPercentInShadow()
    {
        double percentInShadow = 0;
        for(int theta = 0; theta < 360; theta++){
            double xdiff = StaticZap.RADIUS/StaticZap.GRANULARITY * Math.cos(Math.toRadians(theta));
            double ydiff = StaticZap.RADIUS/StaticZap.GRANULARITY * Math.sin(Math.toRadians(theta));
            Line2D.Double radius = new Line2D.Double(internalX, internalY, internalX+xdiff, internalY+ydiff);
            double minDist = StaticZap.MAX_DISTANCE/StaticZap.GRANULARITY;
            for(Line2D wall : getLinesWithinRadius())
            {
                if(wall.intersectsLine(radius))
                {
                    double tempDist = wall.ptLineDist(internalX, internalY);
                    if(tempDist == 0) {
                        isOnALine = StaticZap.EBOOL.YES;
                        this.percentInShadow = 100;
                        neverPlaceLightHere();
                        return;
                    }
                    if(tempDist < minDist)
                        minDist = tempDist;
                }
            }
            distanceFromWall = minDist;
            if(minDist != StaticZap.MAX_DISTANCE/StaticZap.GRANULARITY)
                percentInShadow += 1 - (minDist / (StaticZap.RADIUS/StaticZap.GRANULARITY));
        }
        
        if(isOnALine != StaticZap.EBOOL.YES)
            isOnALine = StaticZap.EBOOL.NO;
        
        this.percentInShadow = percentInShadow / 360;
    }

    public double getPercentInShadow()
    {
        if(percentInShadow == -1)
            setPercentInShadow();
        return percentInShadow;
    }

    private boolean isOnALine()
    {
        if(isOnALine == StaticZap.EBOOL.UNKNOWN) {
            setIsOnALine();
        } 
        
        if(isOnALine == StaticZap.EBOOL.YES) {
            return true;
        } else { //false
            return false;
        }
    }
    
    private void setLinesWithinRadius()
    {
        Set<Line2D> walls = board.getWalls();
        linesWithinRadius = new HashSet<Line2D>();
        for(Line2D wall : walls) {
            if(wall.ptLineDist(internalX, internalY) <= StaticZap.RADIUS / StaticZap.GRANULARITY)
                linesWithinRadius.add(wall);
        }
    }

    public Set<Line2D> getLinesWithinRadius()
    {
        if(linesWithinRadius == null)
            setLinesWithinRadius();
        return linesWithinRadius;
    }
    
    //returns internal representation
    public Point2D.Double getInternalPoint() {
        return new Point2D.Double(internalX, internalY);
    }
    
    public Point2D.Double getExternalPoint() {
        return new Point2D.Double(x, y);
    }

	public double getDistanceFromWall() {
		return distanceFromWall;
	}

	public void setDistanceFromAllWalls(double distanceFromAllWalls) {
		this.distanceFromAllWalls = distanceFromAllWalls;
	}

	public double getDistanceFromAllWalls() {
		return distanceFromAllWalls;
	}

    
}
